package com.fan.demo2;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;

/**
 * 
  * 标准分片策略：精准分片算法、范围分片算法的实现;
  * 此处对 crt.event_cert 进行分片，分片键为 createTime;
 * 2021年之前的数据都存放于 event_cert;
 * 2021年及之后均按照季度存放，一年四张表，如 event_cert_202101、event_cert_202102
 *
 */
public class PreciseAndRangShardingAlgorithm implements PreciseShardingAlgorithm<Date>, RangeShardingAlgorithm<Date> {

	private final Logger LOGGER = LoggerFactory.getLogger(PreciseAndRangShardingAlgorithm.class);

	private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
	
	/**
	  * 表的分隔符 
	 */
	private final String SPILT_SYMBOL = "_";
	

	@Override
	public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Date> shardingValue) {
		Date createTime = shardingValue.getValue();
		if (null == createTime) {
			throw new RuntimeException("The shardingValue should not be null!");
		}
		if (availableTargetNames.size() <= 0) {
			throw new RuntimeException("There is no availableTargetTableNames!");
		}

		String formatDate = simpleDateFormat.format(createTime);
		String tableSuffix = formatDate.substring(0, 4) + "0" + getQuarter(createTime);
		
		for (String tableName : availableTargetNames) {
			if (tableName.endsWith(tableSuffix)) {
				return tableName;
			}
		}

		return shardingValue.getLogicTableName();
	}

	@Override
	public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Date> shardingValue) {
		if (availableTargetNames.size() <= 0) {
			throw new RuntimeException("There is no availableTargetTableNames!");
		}
		
		Collection<String> resultTables = new LinkedHashSet<>(availableTargetNames.size());

		Range<Date> createTimeRange = shardingValue.getValueRange();
		if (!createTimeRange.hasLowerBound() && !createTimeRange.hasUpperBound()) {
			LOGGER.warn("The shardingValue need lower endpoint and upper endpoint!");
			return availableTargetNames;
		}

		Date lowerDate = createTimeRange.lowerEndpoint();
        Date upperDate = createTimeRange.upperEndpoint();
		String lowerDateStr = simpleDateFormat.format(lowerDate);
		String upperDateStr = simpleDateFormat.format(upperDate);

		if (lowerDateStr.compareTo(upperDateStr) > 0) {
			LOGGER.warn("The upper endpoint should be greater than lower endpoint");
			return availableTargetNames;
		}

		String suffixOfLower = lowerDateStr.substring(0, 4) + "0" + getQuarter(lowerDate);
		String suffixOfUpper = upperDateStr.substring(0, 4) + "0" + getQuarter(upperDate);

		for (String tableName : availableTargetNames) {
			String tableSuffix = tableName.substring(tableName.lastIndexOf(SPILT_SYMBOL) + 1);
			if (!tableName.equals(shardingValue.getLogicTableName())) {
				if (tableSuffix.compareTo(suffixOfLower) >= 0 && tableSuffix.compareTo(suffixOfUpper) <= 0) {
					resultTables.add(tableName);
				}
			}
		}
		
		return resultTables;
	}

	/**
	 * 获取月份对应的季度
	 *
	 * @param date
	 * @return
	 */
	public static int getQuarter(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int quarter = ((calendar.get(Calendar.MONTH) + 1) + 2) / 3;
		return quarter;
	}
}
